勝負判斷是 Minesweeper 的核心流程之一:當玩家不小心踩到地雷時應立即結束遊戲;當玩家揭開了所有非地雷格子時則判定勝利。本篇以現有的資料結構(Cell
、Board
、Game
)為基礎,示範實作、解釋關鍵邏輯、並提供可測試的範例與驗收項目。
IsMine == true
→ IsGameOver = true
。Remaining
)」變為 0,或遍歷確認所有非雷格皆為 Revealed
→ IsPlayerWin = true
。Remaining = Rows*Cols - mineCount
(開始時尚未揭開的安全格子數)。IsMine == true
:把該格設為 IsRevealed
,把 Game.IsGameOver = true
,並結束流程(可顯示所有地雷)。IsRevealed = true
,Remaining--
。AdjacentMines == 0
→ 執行 flood-fill(BFS/DFS)展開相鄰安全格(同時減少 Remaining
)。CheckIsPlayerWin()
判斷是否勝利。Remaining == 0
→ IsPlayerWin = true
(視需求:IsPlayerWin 會鎖定遊戲輸入)。Remaining==0
為標準。func (g *GameLayout) Update() error {
// 當狀態為遊戲結束
if g.gameInstance.IsGameOver || g.gameInstance.IsPlayerWin {
return nil
}
// 偵測 mouse 左鍵 click 事件
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
g.handlePositionClickEvent(func(row, col int) {
// 檢查是否踩到地雷
if g.gameInstance.Board.GetCell(row, col).IsMine {
g.gameInstance.IsGameOver = true
}
// 執行 Flood Fill - 更新踩到之後的更新
g.gameInstance.Board.Reveal(row, col)
// 檢查是否達到勝利條件
if !g.gameInstance.IsGameOver {
g.gameInstance.IsPlayerWin = g.gameInstance.Board.CheckIsPlayerWin()
}
})
}
// 偵測 mouse 右鍵 click 事件
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonRight) {
// 標記該位置格子
g.handlePositionClickEvent(func(row, col int) {
g.gameInstance.Board.ToggleFlag(row, col)
})
}
return nil
}
// CheckIsPlayerWin - 檢查是否所有該非地雷的格子都有被掀開
func (board *Board) CheckIsPlayerWin() bool {
return board.remainingUnRevealedCells == 0
}
// revealMines - 顯示所有 Mines
func (board *Board) revealMines() {
for _, mineCoord := range board.mineCoords {
if !board.cells[mineCoord.Row][mineCoord.Col].Flagged &&
!board.cells[mineCoord.Row][mineCoord.Col].Revealed {
board.cells[mineCoord.Row][mineCoord.Col].Revealed = true
}
if board.cells[mineCoord.Row][mineCoord.Col].Flagged {
board.cells[mineCoord.Row][mineCoord.Col].Revealed = true
}
}
}
remainingUnRevealedCells--
// drawCoverOnGameOver - 畫出無法操作的灰色遮罩
func (g *GameLayout) drawCoverOnGameOver(screen *ebiten.Image) {
w, h := ScreenWidth, ScreenHeight-PanelHeight
vector.DrawFilledRect(
screen,
0, PanelHeight, // x, y
float32(w), float32(h), // width, height
color.RGBA{0, 0, 0, 128}, // 半透明黑色 (128 = 約 50% 透明)
false,
)
}
// getColorStatus - 根據 IsGameOver 與 IsPlayerWin 來找出對 message, bgColor
func (g *GameLayout) getColorStatus() (string, color.RGBA) {
bgColor := color.RGBA{100, 100, 0x10, 0xFF}
status := "playing"
if g.gameInstance.IsGameOver {
status = "game over"
bgColor = color.RGBA{150, 0, 0x10, 0xFF}
}
if g.gameInstance.IsPlayerWin {
status = "you win"
bgColor = color.RGBA{200, 200, 0, 0xFF}
}
return status, bgColor
}